<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title></title>
  <script src="words.js"></script>
  <style>
    .word-container {
      width: 100vw;
      max-width: 300px;
      border-right: 1px solid #ccc;
      position: fixed;
      left: 0;
      top: 0;
      z-index: 99;
    }

    #menu {
      position: fixed;
      right: 0;
      top: 50vh;
      transform: translate(0, -50%);
    }

    #menuList {
      position: fixed;
      width: 300px;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: white;
      grid-template-columns: repeat(2, 1fr);
      gap: 10px;
    }

    .toggle-button {
      background-color: #f1f1f1;
      border: none;
      margin: 0;
      cursor: pointer;
      width: 100%;
      height: 43px;
      text-align: left;
    }

    .c_wordList {
      display: none;
      /* 默认隐藏 */
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
      list-style-type: none;
      height: calc(100vh - 43px);
      overflow: auto;
      background-color: white;
    }

    .c_wordList.show {
      display: block;
    }

    .word-item {
      padding: 10px;
      border-bottom: 1px solid #ccc;
    }

    .word-item:last-child {
      border-bottom: none;
    }

    .word-string {
      font-weight: bold;
      color: #333;
    }

    .word-chinese {
      color: #666;
      margin-left: 10px;
    }

    .center-container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      text-align: center;
    }

    button {
      margin: 10px;
      padding: 10px 20px;
      font-size: clamp(8px,
          8px + (24 - 8) * ((100vw - 300px) / (1600 - 300)) px,
          24px);
      cursor: pointer;
      border: none;
      background-color: #007bff;
      color: white;
      border-radius: 5px;
    }

    button:hover {
      background-color: #0056b3;
    }

    button:disabled {
      background-color: #ccc;
      cursor: not-allowed;
    }

    .pronunciation {}
  </style>
  <script>
    let index = 0; //当前显示的单词索引
    let current = 0; // 当前显示第几个单词
    let studyType = 1; // 1为课程单词；2为收藏的课程单词；3为全局收藏单词
    let currentCourse = 0;
    let d_hideOrShowPronunciation = true; // true为显示
    let d_hideOrShowWord = true; // true为显示
    let d_hideOrShowChinese = true; // true为显示
    let d_hideOrShowDictionaryForm = true; // true为显示
    let autoPlayNum = 3;
    let wordList = [];
    let array = [0];
    let isAutoOn = false;
    loadSet();
    document.addEventListener("DOMContentLoaded", () => {
      createWordListContainer();
    });
    document.addEventListener("keydown", (event) => {
      if (document.getElementById("courseInput").matches(':focus')) {
        return;
      }
      if (document.getElementById("inputPlayNum").matches(':focus')) {
        return;
      }
      // 检查是否按下了某个快捷键
      const key = event.key.toLowerCase();
      const button = document.querySelector(`button[data-shortcut="${key}"]`);
      if (button) {
        button.click(); // 触发对应按钮的点击事件
      }
      if (key == "arrowdown") {
        directNext();
      }
      if (key == "arrowup") {
        preTen();
      }
      if (key == "a") {
        console.log(key);
        document.getElementById("courseInput").focus();
      }
      if (key == "escape") {
        showAndHideMenu()
      }
    });

    function updateDisplay() {
      const container = document.querySelector(".center-container");
      container.innerHTML = "";
      const currentDom = document.createElement("div");
      currentDom.innerHTML = `
            <p>第 ${current + 1} 个;总 ${wordList.length} 个</p>
            `;
      container.appendChild(currentDom);
      try {
        wordList[index].string;
      } catch (error) {
        container.innerHTML = "<p>无数据。</p>";
        return;
      }
      const parsed = parseWordAndPronunciation(wordList[index].string);

      if (parsed.length === 0) {
        container.innerHTML = "<p>无法解析单词和发音。</p>";
        return;
      }
      const word = document.createElement("table");
      word.className = "word";
      word.style.fontSize = "32px";
      const row1 = document.createElement("tr");
      parsed.forEach((item) => {
        const div = document.createElement("td");
        div.innerHTML = `
                    <span class='pronunciation'> ${item.pronunciation}</span>
                `;
        row1.appendChild(div);
      });
      word.appendChild(row1);
      const row2 = document.createElement("tr");
      parsed.forEach((item) => {
        const div = document.createElement("td");
        div.innerHTML = `
                    <span class='css_word'> ${item.word}</span>
                `;
        row2.appendChild(div);
      });
      word.appendChild(row2);
      container.appendChild(word);
      if (wordList[index].Chinese) {
        const div = document.createElement("div");
        div.innerHTML += `<p class='css_Chinese'>中文意思： ${wordList[index].Chinese}</p>`;
        div.innerHTML += `<p class='css_Chinese'>例句： ${wordList[index].example}</p>`;
        container.appendChild(div);
      }
      if (wordList[index].type) {
        const div = document.createElement("div");
        div.innerHTML += `<p class='css_type'>类型： ${wordList[index].type}</p>`;
        container.appendChild(div);
      }
      if (wordList[index].resource) {
        const div = document.createElement("div");
        div.innerHTML += `<p class='css_resource css_dictionaryForm'>词源： ${wordList[index].resource}</p>`;
        container.appendChild(div);
      }
      if (wordList[index].dictionaryForm) {
        const div = document.createElement("div");
        div.innerHTML += `<p class='css_dictionaryForm'>简体形： ${wordList[index].dictionaryForm}</p>`;
        container.appendChild(div);
      }
      if (d_hideOrShowPronunciation == false) {
        hideOrShowPronunciation();
      }
      if (d_hideOrShowWord == false) {
        hideOrShowWord();
      }
      if (d_hideOrShowChinese == false) {
        hideOrShowChinese();
      }
      if (d_hideOrShowDictionaryForm == false) {
        hideOrShowDictionaryForm();
      }
      const buttonList = document.createElement("div");
      buttonList.style.display = "grid";
      buttonList.style.gridTemplateColumns = "repeat(2, 1fr)";
      buttonList.style.gap = "10px";
      container.appendChild(buttonList);
      createButton(
        buttonList,
        "隐藏或显示读音",
        hideOrShowPronunciation,
        "1"
      );
      createButton(buttonList, "隐藏或显示意思", hideOrShowChinese, "2");
      createButton(
        buttonList,
        "隐藏或显示简体形",
        hideOrShowDictionaryForm,
        "3"
      );
      createButton(buttonList, "隐藏或显示单词", hideOrShowWord, "4");
      createButton(buttonList, "网易有道读", play, "5");
      createButton(buttonList, "机器读", speakWord, "6");
      createButton(buttonList, "收藏在本课", collectOnThere, "7");
      createButton(buttonList, "收藏在全局", collectOnGloble, "8");
      createButton(buttonList, "上一个", preOne, "arrowleft");
      createButton(buttonList, "下一个", randomNext, "arrowright");
    }
    function createWordListContainer() {
      // 获取单词列表容器
      const wordListContainer = document.getElementById("wordListContainer");
      wordListContainer.innerHTML = "";
      if (!wordListContainer) {
        console.error('Element with id "wordListContainer" not found!');
        return;
      }
      if (wordList) {
        wordList.forEach((item, index) => {
          const div = document.createElement("div");
          div.className = "word-item";
          div.innerHTML = `<span class="word-string" id='${index}' >${item.string}</span><span class="word-chinese">${item.Chinese}</span>`;
          div.onclick = () => clickListItem(index);
          wordListContainer.appendChild(div);
        });
      } else {
        const div = document.createElement("div");
        div.className = "word-item";
        div.innerHTML = `<span class="word-string">无数据</span>`;
        div.onclick = () => clickListItem(index);
        wordListContainer.appendChild(div);
      }
    }
    function isObjectEqual(a, b) {
      if (a === b) return true; // 快速路径，如果两个对象引用相同则直接返回 true
      if (a == null || b == null) return false; // 如果其中一个为 null 或 undefined，则返回 false
      if (typeof a !== "object" || typeof b !== "object") return false; // 确保两者都是对象

      const keysA = Object.keys(a);
      const keysB = Object.keys(b);

      if (keysA.length !== keysB.length) return false;

      for (let key of keysA) {
        if (!keysB.includes(key)) return false;
        if (!isObjectEqual(a[key], b[key])) return false;
      }

      return true;
    }
    function containsObject(obj, list) {
      return list.some((item) => isObjectEqual(item, obj));
    }
    function parseWordAndPronunciation(str) {
      if (!str) {
        console.error("输入字符串为空");
        return [];
      }

      let result = [];
      const regex = /\[(.*?)\]\((.*?)\)/g; // 修正后的正则表达式
      let match;
      while ((match = regex.exec(str)) !== null) {
        result.push({
          word: match[1], // 提取单词部分
          pronunciation: match[2], // 提取发音部分
        });
      }

      if (result.length === 0) {
        console.warn("未找到匹配的单词和发音");
      }

      return result;
    }

    function createButton(parentElement, text, onClickHandler, shortcutKey) {
      const button = document.createElement("button");
      button.textContent = text;
      if (shortcutKey) {
        button.textContent += ` (${shortcutKey.toUpperCase()})`;
        button.setAttribute("data-shortcut", shortcutKey.toLowerCase());
      }
      button.onclick = onClickHandler;
      parentElement.appendChild(button);
    }
    function addFuncToElement(func, querySelector, eventListener) {
      document.querySelector(querySelector).addEventListener(eventListener, () => {
        func()
      });
    }
    function randomNext() {
      if (current < array.length - 1) {
        current = current + 1;
        index = array[current];
      } else {
        if (array.length === wordList.length) {
          alert("已经遍历完所有单词！");
          return;
        }
        let temp;
        do {
          temp = Math.floor(Math.random() * wordList.length);
        } while (array.includes(temp));
        array.push(temp);
        index = temp;
        current = array.length - 1;
      }
      updateDisplay();
    }
    function directNext() {
      if (current < array.length - 1) {
        current = current + 1;
        index = array[current];
      } else {
        if (array.length === wordList.length) {
          alert("已经遍历完所有单词！");
          return;
        }
        let i = 1;
        var temp = -1;
        do {
          index++
          temp = (index) % (wordList.length);
          if (i++ == 99) break
        } while (array.includes(temp));
        array.push(temp);
        index = temp;
        current = array.length - 1;
      }
      updateDisplay();
    }
    function clickListItem(params) {
      if (array.includes(params)) {
        current = array.indexOf(params);
        index = array[current];
      } else {
        array.push(params);
        current = current + 1;
        index = array[current];
      }
      updateDisplay();
    }
    function preOne() {
      if (current > 0) {
        current = current - 1;
        index = array[current];
        updateDisplay();
      } else {
        alert("已经是第一个单词！");
      }
    }
    function preTen() {
      if (current > 10) {
        current = current - 10;
        index = array[current];
        updateDisplay();
      } else {
        current = 0;
        index = array[current];
        updateDisplay();
      }
    }
    function hideOrShowPronunciation() {
      const domList = document.getElementsByClassName("pronunciation");
      if (domList.length === 0) {
        console.error("No elements with class 'pronunciation' found.");
        return;
      }
      for (let i = 0; i < domList.length; i++) {
        const dom = domList[i];
        if (dom.style.display !== "none") {
          d_hideOrShowPronunciation = false;
          dom.style.display = "none"; // 隐藏元素
        } else {
          d_hideOrShowPronunciation = true;
          dom.style.display = "block"; // 显示元素
        }
      }
      localStorage.setItem(`d_hideOrShowPronunciation`, JSON.stringify(d_hideOrShowPronunciation))
    }
    function hideOrShowWord() {
      const domList = document.getElementsByClassName("css_word");
      if (domList.length === 0) {
        console.error("No elements with class 'css_word' found.");
        return;
      }
      for (let i = 0; i < domList.length; i++) {
        const dom = domList[i];
        if (dom.style.display !== "none") {
          d_hideOrShowWord = false;
          dom.style.display = "none"; // 隐藏元素
        } else {
          d_hideOrShowWord = true;
          dom.style.display = "block"; // 显示元素
        }
      }
      localStorage.setItem(`d_hideOrShowWord`, JSON.stringify(d_hideOrShowWord))
    }
    function hideOrShowDictionaryForm() {
      const domList = document.getElementsByClassName("css_dictionaryForm");
      if (domList.length === 0) {
        console.error("No elements with class 'css_dictionaryForm' found.");
        return;
      }
      for (let i = 0; i < domList.length; i++) {
        const dom = domList[i];
        if (dom.style.display !== "none") {
          d_hideOrShowDictionaryForm = false;
          dom.style.display = "none"; // 隐藏元素
        } else {
          d_hideOrShowDictionaryForm = true;
          dom.style.display = "block"; // 显示元素
        }
      }
      localStorage.setItem(`d_hideOrShowDictionaryForm`, JSON.stringify(d_hideOrShowDictionaryForm))
    }
    function hideOrShowChinese() {
      const domList = document.getElementsByClassName("css_Chinese");
      if (domList.length === 0) {
        console.error("No elements with class 'css_Chinese' found.");
        return;
      }
      for (let i = 0; i < domList.length; i++) {
        const dom = domList[i];
        if (dom.style.display !== "none") {
          d_hideOrShowChinese = false;
          dom.style.display = "none"; // 隐藏元素
        } else {
          d_hideOrShowChinese = true;
          dom.style.display = "block"; // 显示元素
        }
      }
      localStorage.setItem(`d_hideOrShowChinese`, JSON.stringify(d_hideOrShowChinese))
    }
    function play() {
      return new Promise((resolve, reject) => {
        const parsed = parseWordAndPronunciation(wordList[index].string);
        const word = parsed.map((item) => item.word).join("");

        const audioUrl = `http://dict.youdao.com/dictvoice?le=jap&audio=${encodeURIComponent(
          word
        )}&type=3`;

        const audio = new Audio(audioUrl);

        // 监听音频的 ended 事件
        audio.addEventListener('ended', () => {
          resolve(true); // 音频播放结束时，完成 Promise 并返回 true
        });

        // 监听音频的 error 事件
        audio.addEventListener('error', (e) => {
          console.error("播放失败:", e);
          resolve(false); // 播放失败时，完成 Promise 并返回 false
        });

        // 播放音频
        audio.play().catch((error) => {
          console.error("播放失败:", error);
          resolve(false); // 如果 play() 本身失败，也完成 Promise
        });
      });
    }
    // 这个函数现在可以像一个 Promise 一样被 await
    function speak(text, lang) {
      return new Promise((resolve) => {
        if ("speechSynthesis" in window) {
          const utterance = new SpeechSynthesisUtterance(text);
          utterance.lang = lang;
          utterance.rate = 1;
          utterance.pitch = 1;

          // 朗读结束时，调用 resolve() 来完成 Promise
          utterance.onend = () => {
            resolve();
          };
          // 如果出现错误，也调用 resolve()，避免程序卡住
          utterance.onerror = (event) => {
            console.error('SpeechSynthesisUtterance.onerror', event);
            resolve();
          };

          window.speechSynthesis.speak(utterance);
        } else {
          alert("您的浏览器不支持 Web Speech API，请尝试使用 Chrome 或 Edge 浏览器。");
          resolve(); // 在不支持的情况下立即完成
        }
      });
    }
    async function speakWord() {
      const parsed = parseWordAndPronunciation(wordList[index].string);
      const word = parsed.map((item) => item.word).join("");
      await speak(word, "ja-JP");
    }

    async function speakChinese() {
      const chinese = wordList[index].Chinese;
      await speak(chinese, "zh-CN");
    }
    function collectOnThere() {
      let word = wordList[index];
      console.log(word);
      let collectThereWordList = JSON.parse(
        localStorage.getItem(`${currentCourse}wordList`)
      );
      if (collectThereWordList && Array.isArray(collectThereWordList)) {
        if (!containsObject(word, collectThereWordList)) {
          collectThereWordList.push(word);
          alert("收藏成功！");
        }
        else {
          if (studyType == 2) {
            // 如果 word 已经在列表中，则移除它
            collectThereWordList = collectThereWordList.filter(item => !isObjectEqual(item, word));
            alert("取消收藏！");
          } else {
            alert("已收藏！");
          }
        }
      } else {
        collectThereWordList = [];
        collectThereWordList.push(word);
        alert("收藏成功！");
      }
      localStorage.setItem(
        `${currentCourse}wordList`,
        JSON.stringify(collectThereWordList)
      );
    }
    function collectOnGloble() {
      let word = wordList[index];
      console.log(word);
      let collectGlobleWordList = JSON.parse(
        localStorage.getItem(`GlobleWordList`)
      );
      if (collectGlobleWordList && Array.isArray(collectGlobleWordList)) {
        if (!containsObject(word, collectGlobleWordList)) {
          collectGlobleWordList.push(word);
          alert("全局收藏成功！");
        }
        else {
          if (studyType === 3) {
            // 如果 word 已经在列表中，则移除它
            collectGlobleWordList = collectGlobleWordList.filter(item => !isObjectEqual(item, word));
            alert("取消全局收藏成功！");
          } else {
            alert("已全局收藏！");
          }
        }
      } else {
        collectGlobleWordList = [];
        collectGlobleWordList.push(word);
        alert("全局收藏成功！");
      }

      localStorage.setItem(
        "Globle" + `WordList`,
        JSON.stringify(collectGlobleWordList)
      );
    }
    function changeThereCollectWordList() {
      let collectThereWordList = JSON.parse(
        localStorage.getItem(`${currentCourse}wordList`)
      );
      wordList = collectThereWordList;
      studyType = 2;
      index = 0;
      current = 0;
      array = [0];
      createWordListContainer();
      updateDisplay();
    }
    function changeGlobleCollectWordList() {
      let collectGlobleWordList = JSON.parse(
        localStorage.getItem("Globle" + `WordList`)
      );
      wordList = collectGlobleWordList;
      studyType = 3;
      index = 0;
      current = 0;
      array = [0];
      createWordListContainer();
      updateDisplay();
    }
    async function switchWordList() {
      const courseInput = document.getElementById("courseInput").value.trim();
      currentCourse = courseInput;
      wordList = [];
      // 将用户输入按分号分割成多个部分
      const parts = courseInput.split(";");

      // 遍历每个部分
      parts.forEach((part) => {
        part = part.trim(); // 去除空格

        if (part.includes("-")) {
          // 如果包含 "-"，表示这是一个范围
          const [start, end] = part
            .split("-")
            .map((num) => parseInt(num.trim(), 10));

          if (isNaN(start) || isNaN(end) || start > end) {
            throw new Error(`无效的范围: ${part}`);
          }

          // 将范围内的所有课程编号加入 wordList
          for (let i = start; i <= end; i++) {
            if (God[`WordList${i}`]) {
              wordList = wordList.concat(God[`WordList${i}`]);
            } else {
              console.warn(`WordList${i} 不存在`);
            }
          }
        } else {
          // 如果是单个数字
          const courseNumber = parseInt(part, 10);

          if (isNaN(courseNumber)) {
            throw new Error(`无效的课程编号: ${part}`);
          }

          // 将对应的单词列表加入 wordList
          if (God[`WordList${courseNumber}`]) {
            wordList = wordList.concat(God[`WordList${courseNumber}`]);
          } else {
            console.warn(`WordList${courseNumber} 不存在`);
          }
        }
      });

      // 检查是否成功加载了单词列表
      if (wordList.length === 0) {
        throw new Error("未找到任何有效的单词列表");
      }

      // 初始化其他状态变量
      index = 0;
      current = 0;
      array = [0];
      studyType = 1;
      // 创建单词列表容器并更新显示
      createWordListContainer();
      await updateDisplay();
      document.getElementById("desideCourse").focus();
    }
    function showAndHideMenu() {
      let element = document.getElementById("menuList")
      if (element.style.display === "none") {
        element.style.display = "grid"
      } else {
        element.style.display = "none"
      }
    }
    async function auto() {
      const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
      while (current < wordList.length) {
        console.log(isAutoOn);
        if (!isAutoOn) {
          return
        }
        if (autoPlayNum <= 0) {
          autoPlayNum = 1
        }
        for (let i = 0; i < autoPlayNum; i++) {
          const audioPlayed = await play();
          if (audioPlayed) {
            await delay(500);
            await speakChinese();
            await delay(500);
          } else {
            // 如果 play() 失败，则 fallback 到 speakWord()
            await speakWord();
            await delay(500);
            await speakChinese();
            await delay(500);
          }
        }
        randomNext();
      }
    }
    function loadSet() {
      if (!JSON.parse(localStorage.getItem(`d_hideOrShowPronunciation`))) {
        d_hideOrShowPronunciation = JSON.parse(localStorage.getItem(`d_hideOrShowPronunciation`));
      }
      if (!JSON.parse(localStorage.getItem(`d_hideOrShowWord`))) {
        d_hideOrShowWord = JSON.parse(localStorage.getItem(`d_hideOrShowWord`));
      }
      if (!JSON.parse(localStorage.getItem(`d_hideOrShowChinese`))) {
        d_hideOrShowChinese = JSON.parse(localStorage.getItem(`d_hideOrShowChinese`));
      }
      if (!JSON.parse(localStorage.getItem(`d_hideOrShowDictionaryForm`))) {
        d_hideOrShowDictionaryForm = JSON.parse(localStorage.getItem(`d_hideOrShowDictionaryForm`));
      }
    }
    window.onload = function () {
      updateDisplay();
      const collectOnThereButtonElement = document.getElementById(
        "collectOnThereButton"
      );
      collectOnThereButtonElement.onclick = changeThereCollectWordList;
      const collectOnGlobleButtonElement = document.getElementById(
        "collectOnGlobleButton"
      );
      collectOnGlobleButtonElement.onclick = changeGlobleCollectWordList;
      document
        .querySelector(".toggle-button")
        .addEventListener("click", () => {
          wordListContainer.classList.toggle("show");
        });
      document
        .querySelector("#desideCourse")
        .addEventListener("click", () => {
          switchWordList();
        });
      // 给输入框绑定键盘按下事件，监听回车键
      document
        .querySelector("#courseInput")
        .addEventListener("keydown", (event) => {
          if (event.key === "Enter") {
            // 检查是否按下了回车键
            switchWordList();
          }
        });
      document
        .querySelector("#inputPlayNum")
        .addEventListener("keydown", (event) => {
          if (event.key === "Enter") {
            isAutoOn = !isAutoOn
            auto()
          }
        });
      document.getElementById("courseInput").focus();
      addFuncToElement(showAndHideMenu, "#menu", "click")
      document.querySelector("#inputPlayNum").addEventListener("input", (event) => {
        if (event.target.value) {
          autoPlayNum = event.target.value
        } else {
          autoPlayNum = 3;
        }
      });
      document.querySelector("#courseInput").addEventListener("input", (event) => {
        if (event.target.value) {
          currentCourse = event.target.value
        }
      });
      addFuncToElement(() => {
        isAutoOn = !isAutoOn
        auto()
      }, "#auto", "click")
    };
  </script>
</head>

<body>
  <div class="word-container">
    <button class="toggle-button">单词列表</button>
    <div class="c_wordList" id="wordListContainer"></div>
  </div>
  <button id="menu">菜单</button>
  <div id="menuList" style="display: none;">
    <input id="inputPlayNum" type="text" placeholder="几" style="width: 15px;">
    <button id="auto" style="display: flex;">自动读遍</button>
  </div>
  <div style="
        display: flex;
        flex-direction: column;
        position: relative;
        top: 0;
        left: 50%;
        transform: translate(-50%, 0);
        width: 100%;
      ">
    <div style="display: flex; justify-content: center">
      <button id="collectOnThereButton"> 本课收藏单词 </button>
      <button id="collectOnGlobleButton">全局收藏单词</button>
    </div>
    <div style="display: flex; justify-content: center">
      <span> 请选择第几课 </span>
      <input type="text" id="courseInput" placeholder="请输入课程编号" />
      <span id="desideCourse" tabindex="-1">确定</span>
    </div>
  </div>
  <div class="center-container"></div>
</body>

</html>